#include "Socket.h"
#include "Logger.h"

using namespace devem;

bool Socket::Create() {
    sock_ = socket(AF_INET, SOCK_STREAM, 0);
    if (sock_ < 0) {
        LOG_WARN("sock_ = %d, create socket fail.", sock_);
        return false;
    }
    return true;
}

bool Socket::Bind(const uint16_t& server_port = defaultPort) {
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = INADDR_ANY;
    local.sin_port = htons(server_port);

    int ret = bind(sock_, (struct sockaddr*)&local, static_cast<socklen_t>(sizeof(local)));
    if (ret < 0) {
        LOG_WARN("bind internet fail.");
        return false;
    }
    return true;
}

bool Socket::Listen(int backlog = defaultBacklog) {
    int ret = listen(sock_, backlog);
    if (ret < 0) {
        LOG_WARN("listen socket fail");
        return false;
    }
    return true;
}

// 服务端并不关心客户端的IP和端口，这里均为输出型参数来打印日志
int Socket::Accept(std::string* client_ip, uint16_t* client_port) {
    struct sockaddr_in peer;
    socklen_t len = sizeof(peer);
    bzero(&peer, len);
    int sock = accept(sock_, (struct sockaddr*)&peer, &len);
    if (sock < 0) {
        LOG_WARN("accept socket fail.");
        return -1;
    }
    *client_ip = inet_ntoa(peer.sin_addr);
    *client_port = ntohs(peer.sin_port);
    return sock;
}

bool Socket::Connect(const std::string& server_ip, const uint16_t& server_port) {
    struct sockaddr_in server;
    socklen_t len = sizeof(server);
    bzero(&server, len);
    // bzero(&server, len) 或者 memset(&server, 0, len)将结构体填充
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = inet_addr(server_ip.c_str());
    server.sin_port = htons(server_port);
    int ret = connect(sock_, (sockaddr*)&server, len);
    if (ret < 0) {
        LOG_WARN("client connect server fail.");
        return false;
    }
    return true;
}

// 读：
ssize_t Socket::Recv(void* buf, int len, int flag = 0) {
    int ret = recv(sock_, buf, len, flag);
    // recv 返回值标准判断
    if (ret == 0) {
        // client shutdown
        LOG_INFO("in sock = %d, client quit, server also quit.", sock_);
        Close();
    } else if (ret < 0) {
        if (errno == EAGAIN || errno == EWOULDBLOCK) {
            // EAGAIN: 表示当前缓冲区中已经没有数据了，在非阻塞的情况下才会有这个报错
            return 0;
        } else if (errno == EINTR) {
            // EINTR: 表示当前的 socket 的阻塞等待，被信号打断了
            return 0;
        } else {
            // fail:
            LOG_WARN("recv error.");
            return -1;
        }
    }
    // success:
    return ret;
}

ssize_t Socket::Send(void* buf, int len, int flag = 0) {
    int ret = send(sock_, buf, len, flag);
    if (ret < 0) {
        return -1;
        LOG_WARN("send error.");
    }
    return ret;
}